/*
 * 程序名：demo5.cpp，此程序用于演示socket的客户端
 */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
using namespace std;

int main(int argc,char *argv[])
{
	if (argc!=3)
    {
	    cout << "Using:./demo5 服务端的IP 服务端的端口\nExample:./demo5 192.168.43.130 5005\n\n"; 
		return -1;
	}

	// 第1步：创建客户端的socket。
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
	if (sockfd==-1)
	{
		perror("socket"); return -1;
	}

	// 第2步：向服务器发起连接请求。
	struct sockaddr_in servaddr; // 用于存放协议、端口和IP地址的结构体。 
	memset(&servaddr,0,sizeof(servaddr));
	servaddr.sin_family = AF_INET;				// ①协议族，固定填AF_INET。
	servaddr.sin_port = htons(atoi(argv[2]));  // ②指定服务端的通信端口
	struct hostent* h;                         // 用于存放服务端IP地址(大端序)的结构体的指针。
	if ( (h = gethostbyname(argv[1])) == nullptr ) // 把域名/主机名/字符串格式的IP转换成结构体。
	{
		cout << "gethostbyname failed.\n" << endl; close(sockfd); return -1;
	}
	memcpy(&servaddr.sin_addr,h->h_addr,h->h_length); // ③指定服务端的IP(大端序)。
	//servaddr.sin_addr.s_addr=inet_addr(argv[1]); // ③指定服务端的IP，只能用IP，不能用域名和主机名。
	if (connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1) // 向服务端发起连接清求。
	{
		perror("connect"); close(sockfd); return -1;
	}
	
	// 第3步：与服务端通讯，客户发送一个请求报文后等待服务端的回复，收到回复后，再发下一个请求报文。
	char buffer[1024];
	for (int ii=0;ii<10;ii++) // 循环3次，将与服务端进行三次通讯。
	{
		int iret;
		memset(buffer,0,sizeof(buffer));
		sprintf(buffer,"这是第%d个超级女生，编号%03d。",ii+1,ii+1); // 生成请求报文内容。
		// 向服务端发送请求报文。
		if ( (iret=send(sockfd,buffer,strlen(buffer),0))<=0)
		{
			perror("send"); break;
		}
		cout << "发送：" << buffer << endl;
		memset(buffer,0,sizeof(buffer));
		// 接收服务端的回应报文，如果服务端没有发送回应报文，recv()函数将阻塞等待。
		if ( (iret=recv(sockfd,buffer,sizeof(buffer),0))<=0)
		{
			cout << "iret=" << iret << endl; break;
		}
		cout << "接收：" << buffer << endl;
		sleep(1);
	}

	// 第4步：关闭socket，释放资源。
	close(sockfd);

	return 0;
}




